package io.kiki.sba.registry.common.model.metaserver;


import io.kiki.sba.registry.common.model.Node.NodeType;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


public class NodeServerOperateInfo {

    private final Set<OperationInfo> metas = new HashSet<>();

    private final Set<OperationInfo> datas = new HashSet<>();

    private final Map<String /*cell*/, Set<OperationInfo>> sessions = new ConcurrentHashMap<>();

    public synchronized Set<OperationInfo> getMetas() {
        return new HashSet<>(metas);
    }


    public synchronized Set<OperationInfo> getDatas() {
        return new HashSet<>(datas);
    }

    public synchronized Map<String /*cell*/, Set<OperationInfo>> getSessions() {
        return new HashMap<>(sessions);
    }


    public synchronized Set<OperationInfo> sessionNodes() {
        Set<OperationInfo> ret = new HashSet<>();
        sessions.forEach((cell, session) -> ret.addAll(session));
        return ret;
    }


    public synchronized int metasSize() {
        return metas.size();
    }


    public synchronized int datasSize() {
        return datas.size();
    }


    public synchronized int sessionSize(String cell) {
        Set<OperationInfo> operationInfos = sessions.get(cell);
        return CollectionUtils.isEmpty(operationInfos) ? 0 : operationInfos.size();
    }

    public synchronized int sessionSize() {

        return Optional.ofNullable(sessions.values()).orElse(Collections.emptySet()).stream().mapToInt(Set::size).sum();
    }


    public synchronized long metaLastOperateTs() {
        if (CollectionUtils.isEmpty(metas)) {
            return 0;
        }
        Long max = metas.stream().map(OperationInfo::getOperateTs).max(Long::compareTo).orElse(0L);
        return max.longValue();
    }


    public synchronized long dataLastOperateTs() {
        if (CollectionUtils.isEmpty(datas)) {
            return 0;
        }
        Long max = datas.stream().map(OperationInfo::getOperateTs).max(Long::compareTo).orElse(0L);
        return max.longValue();
    }

    public synchronized long sessionLastOperateTs() {
        long ret = 0;
        for (Set<OperationInfo> operationInfos : Optional.ofNullable(sessions.values()).orElse(Collections.emptySet())) {
            if (CollectionUtils.isEmpty(operationInfos)) {
                continue;
            }
            Long max = operationInfos.stream().map(OperationInfo::getOperateTs).max(Long::compareTo).orElse(0L);
            if (max.longValue() > ret) {
                ret = max.longValue();
            }
        }
        return ret;
    }


    public synchronized boolean addMetas(String cell, String address) {
        return metas.add(new OperationInfo(NodeType.central_control, cell, address, System.currentTimeMillis()));
    }


    public synchronized boolean removeMetas(String cell, String address) {
        return metas.remove(new OperationInfo(NodeType.central_control, cell, address, System.currentTimeMillis()));
    }


    public synchronized boolean addDatas(String cell, String address) {
        return datas.add(new OperationInfo(NodeType.data_store, cell, address, System.currentTimeMillis()));
    }


    public synchronized boolean removeDatas(String cell, String address) {
        return datas.remove(new OperationInfo(NodeType.data_store, cell, address, System.currentTimeMillis()));
    }


    public synchronized boolean addSessions(String cell, String address) {
        Set<OperationInfo> operationInfos = sessions.computeIfAbsent(cell, k -> new HashSet<>());
        return operationInfos.add(new OperationInfo(NodeType.client_interface, cell, address, System.currentTimeMillis()));
    }


    public synchronized boolean removeSessions(String cell, String address) {

        Set<OperationInfo> operationInfos = sessions.get(cell);
        if (CollectionUtils.isEmpty(operationInfos)) {
            return false;
        }
        return operationInfos.remove(new OperationInfo(NodeType.client_interface, cell, address, System.currentTimeMillis()));
    }


}
